package com.net.oil.update;

import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.net.oil.R;
import com.net.oil.base.BaseActivity;
import com.net.oil.http.AppHttpClient;
import com.net.oil.main.bean.AppVersionInfo;
import com.net.oil.permission.RuntimeRationale;
import com.net.oil.util.FilePathUtil;
import com.net.oil.util.rxbus.RxBus;
import com.yanzhenjie.permission.Action;
import com.yanzhenjie.permission.AndPermission;
import com.yanzhenjie.permission.Permission;
import com.yanzhenjie.permission.Setting;

import java.io.File;
import java.io.IOException;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.FileProvider;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import io.reactivex.Observer;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;
import okio.BufferedSink;
import okio.BufferedSource;
import okio.Okio;

public class UpdateActivity extends BaseActivity {

    private static final int UNKNOWN_APP_SOURCES_REUEST = 0x11;
    public static String APP_INFO = "app_info";
    @BindView(R.id.toolbar_go_back)
    ImageView toolbarGoBack;
    @BindView(R.id.toolbar_title)
    TextView toolbarTitle;
    @BindView(R.id.progress_bar)
    ProgressBar progressBar;
    @BindView(R.id.status_tv)
    TextView statusTv;
    @BindView(R.id.retry_tv)
    TextView retryTv;
    @BindView(R.id.cancel_tv)
    TextView cancelTv;
    @BindView(R.id.download_failed_ly)
    LinearLayout downloadFailedLy;

    private AppVersionInfo appVersionInfo;

    private String fileSavePath;

    private File file;
    private int processLast = 0;
    private Handler handler = new Handler();
    private CompositeDisposable disposable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_upadate);
        ButterKnife.bind(this);
        disposable = new CompositeDisposable();
        initView();
        initData();
        requestPermission(Permission.Group.STORAGE);
    }

    private void initData() {
        appVersionInfo = (AppVersionInfo) getIntent().getSerializableExtra(APP_INFO);
    }

    private void initView() {
        toolbarGoBack.setVisibility(View.GONE);
        toolbarTitle.setText("app更新");
    }

    /**
     * 下载文件
     *
     * @param path 保存路径
     */
    private void downloadFile(final String path) {
        statusTv.setText("下载中");
        try {
            file = new File(path);
            if (!file.getParentFile().exists())
                file.getParentFile().mkdirs();

            if (file.exists()) {
                file.delete();
            }

            AppHttpClient.getDownLoadAppApi().down(appVersionInfo.getUri())
                    .map(new Function<ResponseBody, BufferedSource>() {

                        @Override
                        public BufferedSource apply(ResponseBody responseBody) {
                            return responseBody.source();
                        }
                    })
                    .subscribeOn(Schedulers.io())
                    .observeOn(Schedulers.io())
                    .subscribe(new Observer<BufferedSource>() {
                        @Override
                        public void onSubscribe(Disposable d) {
                            disposable.add(d);
                        }

                        @Override
                        public void onNext(BufferedSource bufferedSource) {
                            try {
                                writeFile(bufferedSource, file);
                            } catch (IOException e) {
                                e.printStackTrace();
                                handler.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        statusTv.setText("下载失败");
                                        downloadFailedLy.setVisibility(View.VISIBLE);
                                    }
                                });
                            }
                        }

                        @Override
                        public void onError(Throwable e) {
                            handler.post(new Runnable() {
                                @Override
                                public void run() {
                                    statusTv.setText("下载失败");
                                    downloadFailedLy.setVisibility(View.VISIBLE);
                                }
                            });
                        }

                        @Override
                        public void onComplete() {
                            processLast = 0;
                            handler.post(new Runnable() {
                                @Override
                                public void run() {
                                    statusTv.setText("下载完成");
                                    installApk();
                                }
                            });
                        }
                    });
            subscribeEvent();
        } catch (Exception e) {
            statusTv.setText("下载失败");
        }
    }

    /**
     * 安装apk
     */
    private void installApk() {

        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                boolean hasInstallPermission = getPackageManager().canRequestPackageInstalls();
                if (!hasInstallPermission) {
                    startInstallPermissionSettingActivity();
                    return;
                }
            }
            Uri apkUri = FileProvider.getUriForFile(this, "com.net.oil.file.provider", new File(fileSavePath));
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
        } else {
            intent.setDataAndType(Uri.fromFile(new File(fileSavePath)), "application/vnd.android.package-archive");
        }
        startActivity(intent);
        finish();
    }

    /**
     * 跳转到设置-允许安装未知来源-页面
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    private void startInstallPermissionSettingActivity() {
        //注意这个是8.0新API
        Uri packageURI = Uri.parse("package:" + getPackageName());
        Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI);
        startActivityForResult(intent, UNKNOWN_APP_SOURCES_REUEST);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == UNKNOWN_APP_SOURCES_REUEST && resultCode == RESULT_OK) {
            installApk();
        }
    }

    /**
     * 下载进度rxbus订阅
     */
    private void subscribeEvent() {
        RxBus.getDefault().toObservable(DownloadBean.class)
                .subscribe(new Observer<DownloadBean>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        disposable.add(d);
                    }

                    @Override
                    public void onNext(DownloadBean downloadBean) {

                        int progress = (int) Math.round(downloadBean.getBytesReaded() / (double) downloadBean.getTotal() * 100);
                        if (progress > processLast + 5) {
                            progressBar.setProgress(progress);
                            processLast = progress;
                        }
                        if (progress == 100) {
                            progressBar.setProgress(progress);
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        subscribeEvent();
                    }

                    @Override
                    public void onComplete() {
                        subscribeEvent();
                    }
                });
    }

    /**
     * 写入文件
     */
    public void writeFile(BufferedSource source, File file) throws IOException {

        BufferedSink bufferedSink = Okio.buffer(Okio.sink(file));
        bufferedSink.writeAll(source);

        bufferedSink.close();
        source.close();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (handler != null) {
            handler.removeCallbacksAndMessages(null);
            handler = null;
        }
        disposable.dispose();
    }

    /**
     * 请求权限.
     */
    private void requestPermission(String... permissions) {
        String per = getString(R.string.file_permission_tip);
        AndPermission.with(this)
                .runtime()
                .permission(permissions)
                .rationale(new RuntimeRationale(per))
                .onGranted(new Action<List<String>>() {
                    @Override
                    public void onAction(List<String> permissions) {
                        /* 请求权限成功，则下载文件 */
                        if (!TextUtils.isEmpty(appVersionInfo.getUri())) {
                            fileSavePath = FilePathUtil.getInstance().getDirDownload(UpdateActivity.this) + "/515app.apk";
                            downloadFile(fileSavePath);
                        } else {
                            statusTv.setText("下载地址有误！");
                        }

                    }
                })
                .onDenied(new Action<List<String>>() {
                    @Override
                    public void onAction(@NonNull List<String> permissions) {
                        if (AndPermission.hasAlwaysDeniedPermission(UpdateActivity.this, permissions)) {
                            /* 请求权限失败，需要去设置里面重新设置！ */
                            showSettingDialog(UpdateActivity.this, permissions);

                        } else {
                            finish();
                        }
                    }
                })
                .start();
    }

    /**
     * 显示设置弹框.
     */
    public void showSettingDialog(Context context, final List<String> permissions) {
        String message = getString(R.string.file_permission_tip);

        new AlertDialog.Builder(context)
                .setCancelable(false)
                .setTitle(R.string.permission_dialog_title)
                .setMessage(message)
                .setPositiveButton(R.string.setting, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        setPermission();
                    }
                })
                .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                })
                .show();
    }

    /**
     * 从设置回来，再次去检验权限
     */
    private void setPermission() {
        AndPermission.with(this)
                .runtime()
                .setting()
                .onComeback(new Setting.Action() {
                    @Override
                    public void onAction() {
                        requestPermission(Permission.Group.STORAGE);
                    }
                })
                .start();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    @OnClick({R.id.retry_tv, R.id.cancel_tv})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.retry_tv:
                requestPermission(Permission.Group.STORAGE);
                break;
            case R.id.cancel_tv:
                finish();
                break;
        }
    }
}
